package com.atguigu.juc;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author tongatong
 * @name ThreadPoolDemo
 * @description
 * 线程最大的特点：线程复用；控制最大并发数；线程管理。
 * 线程池作用：
 *  （1）降低资源损耗。线程的复用，可以降低创建和销毁线程的资源损耗。
 *  （2）提高响应速度。需要的时候直接调用，线程的创建和销毁都需要时间。
 *  （3）提高复用性。
 * 使用：
 *  （1）Executors.newFixedThreadPool(int)。固定N个线程池。
 *  （2）Executors.newSingleThreadExecutor()。线程池中有一个线程。
 *  （3）Executors.newCachedThreadPool()。可扩容的线程池。
 *
 * public ThreadPoolExecutor(int corePoolSize,
 *                               int maximumPoolSize,
 *                               long keepAliveTime,
 *                               TimeUnit unit,
 *                               BlockingQueue<Runnable> workQueue,
 *                               ThreadFactory threadFactory,
 *                               RejectedExecutionHandler handler)
 * 线程池的七大参数：
 *  1. corePoolSize.
 *     核心线程池，必须要创建的N个线程。
 *  2. maximumPoolSize
 *     线程池的最大线程池。
 *  3. keepAliveTime
 *     多余线程空闲时间。超过一定时间，会关闭线程。
 *  4. unit
 *     空闲时间单位。
 *  5. workQueue
 *     任务队列。被提交，但还未被执行的任务。
 *  6. threadFactory
 *     线程工厂，用于创建线程。一般使用默认的。
 *  7. handler
 *     拒绝策略。当达到最大线程数的时候，如何拒绝请求执行的线程。
 *     四大拒绝策略：
 *     （1）CallerRunsPolicy。
 *         如果线程池满了的话，被拒绝的线程，会返回到调用者所处的线程，由调用者执行。
 *     （2）AbortPolicy(默认)
 *         丢弃任务，抛出RejectedExecutionException异常。
 *     （3）DiscardPolicy、
 *         直接丢弃。
 *     （4）DiscardOldestPolicy
 *         丢弃最早进入工作队列（阻塞队列）的线程，并将此次被拒绝的线程加入队列。
 *
 * ☆☆☆线程池的工作原理☆☆☆
 * 1. 创建线程池后，等待请求。
 * 2. 执行execute()方法后
 *    (1) 活动线程小于corePoolSize,创建线程.
 *    (2) 活动线程大于等于corePoolSize,并且小于corePoolSize+工作队列长度,将要执行的线程放入工作队列.
 *    (3) 活动线程大于等于corePoolSize+工作队列长度,创建非核心线程.
 *    (4) 活动线程大于等于maximumPoolSize,触发拒绝策略.
 * 3. 当一个任务完成后,从工作队列中取任务.
 * 4. 所有任务完成,当线程空闲到一定的时间的时候,工作线程回缩到corePoolSize的大小。
 *
 * 在工作中，我们一般采用自定义创建线程池类，threadpoolexecutor
 * 因为固定线程池和单例线程池，工作队列的最大长度是integer.max_value。
 * 可变线程池最大线程数量允许integer.max_value.
 *
 *
 * 核心线程数量的大小（参考值）：
 *  1. CPU密集型任务，CPU核数+1；
 *  2. I/0密集型任务，CPU核数*2；
 *
 *
 * execute()和submit()不同:
 *  （1）返回值。execute()没有返回值，submit()有返回值，为future。
 *  （2）形参。execute()只能传递runnable接口，submit()runnable和callable均可。
 *  （3）异常。execute()抛出异常，submit()内部解决异常。
 *  （4）submit()，使用future.get()方法，取不到值，会一直阻塞。
 *
 * @date 2021/9/5
 * @time 20:15
 */
public class ThreadPoolDemo {
    public static void main(String[] args) {
        //固定线程池
//        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //单个线程池
//        ExecutorService executorService = Executors.newSingleThreadExecutor();
        //可变线程次
        ExecutorService executorService = Executors.newCachedThreadPool();

        try {
            for (int i = 1; i <= 20; i++) {
                int finalI = i;
                executorService.execute(() -> {
                    System.out.println(Thread.currentThread().getName()+"\t"+ finalI);
                });
                /*executorService.submit(() -> {
                    System.out.println(Thread.currentThread().getName()+"\t"+finalI);
                });*/
            }
        } finally {
            executorService.shutdown();
        }
    }
}
